/**
 * Copyright 2015 jianglibo@gmail.com
 *
 */
package com.m3958.logcollector.init;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import com.m3958.logcollector.authenticationtoken.M3958LoginAuthenticationToken;
import com.m3958.logcollector.config.AppConfig;
import com.m3958.logcollector.domain.Role;
import com.m3958.logcollector.domain.TreeBlob;
import com.m3958.logcollector.repository.RoleRepository;
import com.m3958.logcollector.repository.TreeBlobRepository;
import com.m3958.logcollector.userdetail.PersonManager;
import com.m3958.logcollector.util.common.M3958SecurityUtil;
import com.m3958.logcollector.util.common.PersonUtil;
import com.m3958.logcollector.vo.PersonVo;
import com.m3958.logcollector.vo.RoleNames;

/**
 * @author jianglibo@gmail.com
 *         2015年12月11日
 *
 */
@Component
public class AppInit implements InitializingBean {
    
    private static final Logger logger = LoggerFactory.getLogger(AppInit.class);
    
    private final RoleRepository roleRepo;
    
    private final PersonManager personManager;
    
    private final AppConfig appConfig;
    
    private final PersonUtil personUtil;
    
    private final TreeBlobRepository tbRepo;
    
    @Autowired
    public AppInit(RoleRepository roleRepo,PersonManager personManager, PersonUtil personUtil, AppConfig appConfig, TreeBlobRepository tbRepo) {
        this.roleRepo = roleRepo;
        this.personManager = personManager;
        this.appConfig = appConfig;
        this.personUtil = personUtil;
        this.tbRepo = tbRepo;
    }

    /* (non-Javadoc)
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        initRoles();
        initFirstUser();
        initPersonGroupTree();
    }
    
    private void initPersonGroupTree() {
        loginAsSystemManager();
        TreeBlob tb = new TreeBlob("person-group");
        tbRepo.save(tb);
        M3958SecurityUtil.logout();
    }

    /**
     * 
     */
    private void initFirstUser() {
        String un = appConfig.getInitUserName();
        String pwd = appConfig.getInitUserPassword();
        try {
            personManager.loadUserByUsername(un);
        } catch (UsernameNotFoundException e) {
            logger.info("init user not found.");
            logger.info("create init user {}, with password {}", un, pwd);
            PersonVo pvo = personUtil.createUnSavedPersonVo(un, RoleNames.USER);
            personManager.createUser(pvo);
            loginAsPersonManager();
            personUtil.alterRoles(un, RoleNames.PERSON_MANAGER, RoleNames.USER);
            M3958SecurityUtil.logout();
        }
    }
    
    private void initRoles() {
        // @formatter:off
        loginAsRoleCreator();
        RoleNames.allFields().stream()
            .filter(rn -> roleRepo.findByName(rn) == null)
            .map(r -> new Role(r))
            .forEach(r -> {
                try {
                    roleRepo.save(r);
                } catch (Exception e) {
                    logger.info("role {} maybe exists, exception message is: {}", r.getName(), e.getMessage());
                }
            });
        M3958SecurityUtil.logout();
        // @formatter:on
    }
    
    
    private void loginAsPersonManager() {
        M3958LoginAuthenticationToken saut = new M3958LoginAuthenticationToken(
                personUtil.createUnSavedPersonVo("personManager", RoleNames.USER, RoleNames.PERSON_MANAGER));
        M3958SecurityUtil.doLogin(saut);
    }

    private void loginAsSystemManager() {
        M3958LoginAuthenticationToken saut = new M3958LoginAuthenticationToken(
                personUtil.createUnSavedPersonVo("personManager", RoleNames.USER, RoleNames.SYSTEM_MANAGER));
        M3958SecurityUtil.doLogin(saut);
    }

    private void loginAsRoleCreator() {
        M3958LoginAuthenticationToken saut = new M3958LoginAuthenticationToken(
                personUtil.createUnSavedPersonVo("roleInitializer", RoleNames.USER, RoleNames.ROLE_CREATOR));
        M3958SecurityUtil.doLogin(saut);
    }
}
